#include "entity.hpp"

Trie::TrieNode::TrieNode() : rules(vector<Rule*>()), l(nullptr), r(nullptr) {}

Trie::TrieNode * Trie::TrieNode::getNext(int flag) {
    if (flag == 0) {
        if (this->l == nullptr) {
            this->l = new Trie::TrieNode;
        }
        return this->l;
    } else {
        if (this->r == nullptr) {
            this->r = new Trie::TrieNode;
        }
        return this->r;
    }
}

Trie::Trie() {
    this->root = new Trie::TrieNode;
}

void Trie::explore(vector<Rule*> *ret, Trie::TrieNode * const t) {
    if (t->l != nullptr) explore(ret, t->l);
    if (t->r != nullptr) explore(ret, t->r);
    ret->insert(ret->end(), t->rules.begin(), t->rules.end());
}

vector<Rule*> Trie::addAndGetAllRulesUntil(Rule *rule) {
    Trie::TrieNode *t = this->root;
    vector<Rule*> ret(t->rules);

    for (int i = 0; i < rule->priority; i++) {
        long bit = (rule->dstIp >> (31 - i)) & 1;
        t = t->getNext((bit == 0) ? 0 : 1);
        ret.insert(ret.end(), t->rules.begin(), t->rules.end());
    }
    explore(&ret, t);

    t->rules.push_back(rule);
    return ret;
}

int Device::cnt = 0;

Device::Device(const string &name) : name(name), uid((name == "default") ? 0: cnt++) {}

Port* Device::addPortByName(const string &name) {
    Port* p = new Port;
    p->name = name, p->device = this;
    return nameToPort[name] = p;
}

Port* Device::getPortByName(const string &name) {
    if (nameToPort.find(name) == nameToPort.end()) {
        return addPortByName(name);
    }
    return nameToPort[name];
}

vector<Rule*> Device::addAndGetAllRulesUntil(Rule *rule) {
    return this->rules.addAndGetAllRulesUntil(rule);
}